#include "base/listener.h"

static void AcceptCallback(struct evconnlistener *listener,
                           evutil_socket_t fd,
                           struct sockaddr *saddr,
                           int slen,
                           void *ctx) {
  Listener::Ptr live_this = ((Listener*)ctx)->shared_from_this();
  live_this->OnAccept(listener, fd, saddr, slen);
}

static void ErrorCallback(struct evconnlistener *listener, void *ctx) {
  Listener::Ptr live_this = ((Listener*)ctx)->shared_from_this();
  live_this->OnError(listener);
}

Listener::Listener(EventLoop::Ptr event_loop)
  : event_loop_(event_loop) {
}


Listener::~Listener() {
  if (NULL != listener_) {
    evconnlistener_free(listener_);
    listener_ = NULL;
  }
}

bool Listener::Start(const std::string &ip, int port) {
  struct sockaddr_in servaddr;
  memset(&servaddr, 0, sizeof(servaddr));
  servaddr.sin_family = AF_INET;
  servaddr.sin_port = htons(port);
  if (evutil_inet_pton(AF_INET, ip.c_str(), &servaddr.sin_addr) <= 0) {
    std::cout << "inet_pton error!" << std::endl;
    return false;
  }

  int flags = LEV_OPT_CLOSE_ON_FREE | LEV_OPT_CLOSE_ON_EXEC | LEV_OPT_REUSEABLE;

  listener_ = evconnlistener_new_bind(
                event_loop_->GetEventBase(),
                AcceptCallback,
                this,
                flags,
                10,
                (sockaddr*)&servaddr,
                sizeof(sockaddr));
  if (NULL == listener_) {
    std::cout << "Create listener failed!" << std::endl;
    return false;
  }

  evconnlistener_set_error_cb(listener_, ErrorCallback);

  return true;
}

void Listener::OnAccept(struct evconnlistener *listener,
                        evutil_socket_t fd,
                        struct sockaddr *saddr,
                        int slen) {
  SignalAccept(shared_from_this(), fd, saddr, slen);
}

void Listener::OnError(struct evconnlistener *listener) {
  SignalError(shared_from_this());
}
